#include "FileList.h"
#include "Sigin.h"
#include "CryptoUtil.h"
#include <nlohmann/json.hpp>
#include <workflow/MySQLResult.h>
#include <map>
#include <string>
#include <sstream>
#include <iostream>
#include <functional>
using std::map;
using std::string;
using std::function;
using std::ostringstream;
using std::bind;
using namespace protocol;
using namespace wfrest;

using JSON = nlohmann::json;


FileList::FileList(wfrest::HttpServer & server)
:m_server(server)
{
}

struct FileListContext{
    HttpResp * resp;
};

void filelistMysqlCallback2(WFMySQLTask * mysqlTask){
    FileListContext * context = static_cast<FileListContext*>(series_of(mysqlTask)->get_context());
    if(mysqlTask->get_state() !=WFT_STATE_SUCCESS){
        context->resp->String("mysqlTask failed");
        return;
    }

    MySQLResultCursor cursor(mysqlTask->get_resp());

    if(cursor.get_cursor_status()==MYSQL_PACKET_ERROR){
        context->resp->String("error77");
        return ;
    }

    if(cursor.get_cursor_status()==MYSQL_STATUS_GET_RESULT){

        JSON retJs;
        JSON assJs;
        map<string,MySQLCell> row;
        cursor.fetch_row(row);
        do{
            if(row.size()==0){
                context->resp->String("");
                return;
            }
            assJs["FileHash"] = row["hashcode"].as_string();
            assJs["FileName"] = row["filename"].as_string();
            assJs["FileSize"] = row["size"].as_int();
            assJs["UploadAt"] = row["created_at"].as_datetime();
            assJs["LastUpdated"] = row["last_update"].as_datetime();
            retJs.push_back(assJs);

        }while(cursor.fetch_row(row));

        context->resp->String(retJs.dump());

    }else{
            context->resp->String("error44");           
    }

}

void filelistMysqlCallback1(WFMySQLTask * mysqlTask){
    FileListContext * context = static_cast<FileListContext*>(series_of(mysqlTask)->get_context());
    if(mysqlTask->get_state() !=WFT_STATE_SUCCESS){
        context->resp->String("mysqlTask failed");
        return;
    }

    MySQLResultCursor cursor(mysqlTask->get_resp());

    if(cursor.get_cursor_status()==MYSQL_PACKET_ERROR){
        context->resp->String("error11");
        return ;
    }

    if(cursor.get_cursor_status()==MYSQL_STATUS_GET_RESULT){
        map<string,MySQLCell> row;
        cursor.fetch_row(row);
        if(row.size()==0){
            context->resp->String("error22");
            return;
        }
        int id = row["id"].as_int();
        ostringstream oss ;
        oss<<"select * from tbl_user_file where uid = '"<<id<<"';";
        string sql = oss.str();
        WFMySQLTask * mysqltask = WFTaskFactory::create_mysql_task("mysql://root:123@localhost/newCloudDisk",3,filelistMysqlCallback2);
        mysqltask->get_req()->set_query(sql);
        series_of(mysqlTask)->set_context(context);
        series_of(mysqlTask)->push_back(mysqltask);

    }else{
            context->resp->String("error33");           
    }

}


void FileList::filelist_module(){
    m_server.POST("/file/query",[](const HttpReq* req, HttpResp* resp,SeriesWork* series){
        string username;
        string token;
        username = req->query("username");
        token = req->query("token");
        #ifdef DEBUG
            std::cout<<username<<"\n";
            std::cout<<token<<"\n";
        #endif

        if(CryptoUtil::verify_token(token,username)){
            string sql = "select * from tbl_users where username = '"+username+"';";
            WFMySQLTask * mysqltask = WFTaskFactory::create_mysql_task("mysql://root:123@localhost/newCloudDisk",3,filelistMysqlCallback1);
            mysqltask->get_req()->set_query(sql);
            FileListContext * ctx = new FileListContext{resp};

            series->set_context(ctx);
            series->set_callback([ctx](const SeriesWork *){
                delete ctx;
            });

            series->push_back(mysqltask);
        }else{
            resp->String("error99");
        }
    });    
}

void FileList::start(){
    filelist_module();
}